﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		TimeZoneInfo.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 //   File:            TimeZoneInfo.cs
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Data;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace Dexter.Repository.NHibernate.UserTypes {

	[Serializable]
	internal class TimeZoneInfo : IUserType
	{
		#region IUserType Members

		/// <summary>
		/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
		/// </summary>
		/// <param name="x">The <see cref="System.Object"/> to compare with this instance.</param>
		/// <param name="y">The y.</param>
		/// <returns>
		/// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
		/// </returns>
		public new bool Equals ( object x , object y ) {
			if ( ReferenceEquals ( x , y ) ) {
				return true;
			}
			if ( x == null || y == null ) {
				return false;
			}
			return x.Equals ( y );
		}

		/// <summary>
		/// Returns a hash code for this instance.
		/// </summary>
		/// <param name="x">The x.</param>
		/// <returns>
		/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
		/// </returns>
		public int GetHashCode ( object x ) {
			return x == null
			       	? typeof ( System.TimeZoneInfo ).GetHashCode ( ) + 473
			       	: x.GetHashCode ( );
		}

		/// <summary>
		/// Retrieve an instance of the mapped class from a JDBC resultset.
		/// Implementors should handle possibility of null values.
		/// </summary>
		/// <param name="rs">a IDataReader</param>
		/// <param name="names">column names</param>
		/// <param name="owner">the containing entity</param>
		/// <returns></returns>
		/// <exception cref="T:NHibernate.HibernateException">HibernateException</exception>
		public object NullSafeGet ( IDataReader rs , string[] names , object owner ) {
			object obj = NHibernateUtil.String.NullSafeGet ( rs , names[ 0 ] );
			if ( obj == null ) {
				return null;
			}

			var dbValue = ( string ) obj;

			return System.TimeZoneInfo.FindSystemTimeZoneById ( dbValue );
		}

		/// <summary>
		/// Write an instance of the mapped class to a prepared statement.
		/// Implementors should handle possibility of null values.
		/// A multi-column type should be written to parameters starting from index.
		/// </summary>
		/// <param name="cmd">a IDbCommand</param>
		/// <param name="value">the object to write</param>
		/// <param name="index">command parameter index</param>
		/// <exception cref="T:NHibernate.HibernateException">HibernateException</exception>
		public void NullSafeSet ( IDbCommand cmd , object value , int index ) {
			if ( value == null ) {
				( ( IDataParameter ) cmd.Parameters[ index ] ).Value = DBNull.Value;
			}
			else {
				( ( IDataParameter ) cmd.Parameters[ index ] ).Value = ( ( System.TimeZoneInfo ) value ).Id;
			}
		}

		/// <summary>
		/// Return a deep copy of the persistent state, stopping at entities and at collections.
		/// </summary>
		/// <param name="value">generally a collection element or entity field</param>
		/// <returns>a copy</returns>
		public object DeepCopy ( object value ) {
			return value;
		}

		/// <summary>
		/// During merge, replace the existing (<paramref name="target"/>) value in the entity
		/// we are merging to with a new (<paramref name="original"/>) value from the detached
		/// entity we are merging. For immutable objects, or null values, it is safe to simply
		/// return the first parameter. For mutable objects, it is safe to return a copy of the
		/// first parameter. For objects with component values, it might make sense to
		/// recursively replace component values.
		/// </summary>
		/// <param name="original">the value from the detached entity being merged</param>
		/// <param name="target">the value in the managed entity</param>
		/// <param name="owner">the managed entity</param>
		/// <returns>the value to be merged</returns>
		public object Replace ( object original , object target , object owner ) {
			return original;
		}

		/// <summary>
		/// Reconstruct an object from the cacheable representation. At the very least this
		/// method should perform a deep copy if the type is mutable. (optional operation)
		/// </summary>
		/// <param name="cached">the object to be cached</param>
		/// <param name="owner">the owner of the cached object</param>
		/// <returns>
		/// a reconstructed object from the cachable representation
		/// </returns>
		public object Assemble ( object cached , object owner ) {
			return cached;
		}

		/// <summary>
		/// Transform the object into its cacheable representation. At the very least this
		/// method should perform a deep copy if the type is mutable. That may not be enough
		/// for some implementations, however; for example, associations must be cached as
		/// identifier values. (optional operation)
		/// </summary>
		/// <param name="value">the object to be cached</param>
		/// <returns>a cacheable representation of the object</returns>
		public object Disassemble ( object value ) {
			return value;
		}

		/// <summary>
		/// The SQL types for the columns mapped by this type.
		/// </summary>
		/// <value></value>
		public SqlType[] SqlTypes {
			get {
				return new[] {
					new SqlType ( DbType.String )
				};
			}
		}

		/// <summary>
		/// The type returned by <c>NullSafeGet()</c>
		/// </summary>
		/// <value></value>
		public Type ReturnedType {
			get { return typeof ( System.TimeZoneInfo ); }
		}

		/// <summary>
		/// Are objects of this type mutable?
		/// </summary>
		/// <value></value>
		public bool IsMutable {
			get { return false; }
		}

		#endregion
	}
}
